package com.zm;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

public class Junit {
    public static void main(String[] args) {
        Object tester = new MathBizTest();
        testObject(tester);
    }
    public static void testObject(Object tester){
        //收集方法
        List<Method> testMethodList = new ArrayList<>();
        List<Method> beforeMethodList = new ArrayList<>();
        List<Method> afterMethodList = new ArrayList<>();

        Class<?> testerClass = tester.getClass();
        for (Method method : testerClass.getDeclaredMethods()) {
            if(method.getAnnotation(Before.class)!=null){
                beforeMethodList.add(method);
            }else if(method.getAnnotation(Test.class)!=null){
                testMethodList.add(method);
            }else if(method.getAnnotation(After.class)!=null){
                afterMethodList.add(method);
            }
        }
        //测试方法排序
       testMethodList.sort((a,b)->{
           int testa = a.getAnnotation(Test.class).value();
           int testb = b.getAnnotation(Test.class).value();
           return testa - testb;
       });

        List<Method> success = new ArrayList<>();
        List<Method> exception = new ArrayList<>();
        List<Method> fail = new ArrayList<>();

        //执行测试
        for (Method method : testMethodList) {

            //junit 要求测试方法不能有任何参数,且是共有的

            for (Method method1 : beforeMethodList) {
                try {
                    method1.invoke(tester);
                } catch (IllegalAccessException e) {
                    throw new RuntimeException(e);
                } catch (InvocationTargetException e) {
                    throw new RuntimeException(e);
                }
            }


            try {
                method.invoke(tester);
                System.out.println(method.getName()+":测试正常");
                success.add(method);
            } catch (IllegalAccessException e) {
//                throw new RuntimeException(e);
                System.out.println("======== 不会出现的异常 ========");
            } catch (InvocationTargetException e) {
                //业务方法内部出现的异常，都会被该异常所封装
                Throwable cause = e.getCause();
                //cause 才是业务异常
                System.out.println("cause = " + cause);
                if (cause instanceof AssertException){
                    System.out.println(method.getName()+":测试错误");
                    fail.add(method);
                }else {
                    System.out.println(method.getName()+":测试异常");
                    exception.add(method);
                }
//                throw new RuntimeException(e);
            }


            for (Method method1 : afterMethodList) {
                try {
                    method1.invoke(tester);
                } catch (IllegalAccessException e) {
                    throw new RuntimeException(e);
                } catch (InvocationTargetException e) {
                    throw new RuntimeException(e);
                }
            }
        }

        System.out.println("success : " + success);
        System.out.println("exception : " + exception);
        System.out.println("fail : " + fail);

    }
}

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@interface Test{
    int value();
}

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@interface  Before{

}

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@interface  After{

}








class MathBiz {
    // 正常业务方法
    public int add( int a, int b ){
        return a + b;
    }
    // 正常业务方法
    public int div( int a, int b ){
        return a / b;
    }
    // 异常业务方法
    public int sub( int a, int b ){
        int i = 1 / 0;
        return a - b;
    }
    // 错误业务方法
    public int mul( int a, int b ){
        return a * b + 100;
    }
    // 错误业务方法
    public int pow( int a ){
        return a * a + 200;
    }
}

class MathBizTest {
    MathBiz biz;
    @Test(1)
    public void test1(){
        System.out.println("-------- test1 --------");
        int res = biz.add(1, 1);
//        Assert.assertEquals(2, res);
    }
    @Test(3)
    public void test2(){
        System.out.println("-------- test2 --------");
        int res = biz.sub(1, 1);
        Assert.assertEquals(0, res);
    }
    @Test(5)
    public void test3(){
        System.out.println("-------- test3 --------");
        int res = biz.mul(1, 1);
        Assert.assertEquals(1, res);
    }
    @Test(2)
    public void test4(){
        System.out.println("-------- test4 --------");
        int res = biz.div(1, 1);
        Assert.assertEquals(1, res);
    }
    @Test(4)
    public void test5(){
        System.out.println("-------- test5 --------");
        int res = biz.pow(2);
        Assert.assertEquals(4, res);
    }
    // 每个测试方法执行前执行的方法
    @Before
    public void before(){
        System.out.println("======== before =======");
        biz = new MathBiz();
    }
    // 每个测试方法执行后执行的方法
    @After
    public void after(){
        System.out.println("======== after =======");
        biz = null;
    }

}

class Assert {
    public static void assertEquals(Object exp,Object act){
        if(!act.equals(exp)){
            throw new AssertException(String.format("期望值是%s,实际值是%s",exp,act));
        }
    }
}

class AssertException extends RuntimeException{
    public AssertException(String message){
        super(message);
    }
}
